package com.example.ftpfilesync.service;

import com.example.ftpfilesync.config.FtpProperties;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class FileSyncListenerService {

    private static final Logger logger = LoggerFactory.getLogger(FileSyncListenerService.class);

    // 需要忽略的文件扩展名
    private static final Set<String> IGNORED_EXTENSIONS = new HashSet<>();
    
    static {
        IGNORED_EXTENSIONS.add(".swp");     // Vim临时文件
        IGNORED_EXTENSIONS.add(".tmp");     // 临时文件
        IGNORED_EXTENSIONS.add(".temp");    // 临时文件
        IGNORED_EXTENSIONS.add("~");        // 备份文件
        IGNORED_EXTENSIONS.add(".bak");     // 备份文件
        IGNORED_EXTENSIONS.add(".log");     // 日志文件
    }

    private final FtpProperties ftpProperties;
    private final FileStateChecker fileStateChecker;
    private final FtpService ftpService;
    private final LocalFileService localFileService;
    
    // 线程池
    private ExecutorService executorService;

    // 存储已完成同步的项目信息（文件路径 -> 最后同步时间）
    // 键格式: taskId:filePath （taskId为任务ID，用于区分不同任务的同步记录）
    private final ConcurrentHashMap<String, Long> syncedItems = new ConcurrentHashMap<>();

    public FileSyncListenerService(FtpProperties ftpProperties, FileStateChecker fileStateChecker, 
                                   FtpService ftpService, LocalFileService localFileService) {
        this.ftpProperties = ftpProperties;
        this.fileStateChecker = fileStateChecker;
        this.ftpService = ftpService;
        this.localFileService = localFileService;
    }

    @PostConstruct
    public void init() {
        logger.info("文件同步监听服务已启动");
        
        logger.info("使用多任务配置，任务数量: {}", ftpProperties.getSyncTasks().size());
        for (FtpProperties.SyncTask task : ftpProperties.getSyncTasks()) {
            logger.info("任务 [{}] - 源目录: {}, 使用FTP: {}, 启用: {}", 
                task.getName(), task.getSourcePath(), task.isUseFtp(), task.isEnabled());
        }
        
        logger.info("检测已同步文件修改: {}", ftpProperties.isDetectModifiedFiles() ? "是" : "否");
        logger.info("保持文件时间戳一致: {}", ftpProperties.isPreserveTimestamps() ? "是" : "否");
        logger.info("启用多线程同步: {}", ftpProperties.isEnableMultiThread() ? "是" : "否");
        
        // 初始化线程池
        if (ftpProperties.isEnableMultiThread()) {
            this.executorService = Executors.newFixedThreadPool(ftpProperties.getMaxThreads());
            logger.info("初始化线程池，最大线程数: {}", ftpProperties.getMaxThreads());
        }
    }

    @Scheduled(fixedDelayString = "${file-sync.check-interval:5000}")
    public void checkAndSyncDirectories() {
        // 处理多任务配置
        checkAndSyncWithMultipleTasks();
    }

    /**
     * 处理多任务配置
     */
    private void checkAndSyncWithMultipleTasks() {
        for (int i = 0; i < ftpProperties.getSyncTasks().size(); i++) {
            FtpProperties.SyncTask task = ftpProperties.getSyncTasks().get(i);
            
            // 跳过禁用的任务
            if (!task.isEnabled()) {
                continue;
            }
            
            String taskId = "task-" + i + "-" + task.getName();
            
            // 直接处理任务，不使用多线程包装
            processSyncTask(taskId, task);
        }
    }

    /**
     * 处理单个同步任务
     */
    private void processSyncTask(String taskId, FtpProperties.SyncTask task) {
        try {
            // 获取任务配置（支持覆盖全局配置）
            boolean detectModifiedFiles = task.getDetectModifiedFiles() != null ? 
                task.getDetectModifiedFiles() : ftpProperties.isDetectModifiedFiles();
            boolean preserveTimestamps = task.getPreserveTimestamps() != null ? 
                task.getPreserveTimestamps() : ftpProperties.isPreserveTimestamps();
            long largeFileThreshold = task.getLargeFileThreshold() != null ? 
                task.getLargeFileThreshold() : ftpProperties.getLargeFileThreshold();
            
            if (task.isUseFtp()) {
                FtpProperties.Ftp ftpConfig = task.getFtp() != null ? task.getFtp() : ftpProperties.getFtp();
                checkAndSyncWithFtp(taskId, task.getSourcePath(), task.getTargetPath(), 
                    ftpConfig, detectModifiedFiles, preserveTimestamps, largeFileThreshold);
            } else {
                checkAndSyncLocally(taskId, task.getSourcePath(), task.getLocalTargetPath(), 
                    detectModifiedFiles, preserveTimestamps, largeFileThreshold);
            }
        } catch (Exception e) {
            logger.error("处理任务 [{}] 时发生错误", task.getName(), e);
        }
    }

    /**
     * 使用FTP进行文件同步
     *
     * @param taskId 任务ID
     * @param sourcePath 源路径
     * @param targetPath 目标路径
     * @param ftpConfig FTP配置
     * @param detectModifiedFiles 是否检测已修改文件
     * @param preserveTimestamps 是否保持时间戳
     * @param largeFileThreshold 大文件阈值
     */
    private void checkAndSyncWithFtp(String taskId, String sourcePath, String targetPath, 
                                     FtpProperties.Ftp ftpConfig, boolean detectModifiedFiles, 
                                     boolean preserveTimestamps, long largeFileThreshold) {
        if (targetPath == null || targetPath.isEmpty()) {
            logger.warn("任务 [{}] 使用FTP但未配置目标目录", taskId);
            return;
        }

        FTPClient sourceFtpClient = null;
        FTPClient targetFtpClient = null;
        try {
            // 创建FTP客户端（使用任务特定的配置）
            sourceFtpClient = createFTPClient(ftpConfig);
            targetFtpClient = createFTPClient(ftpConfig);

            // 列出源目录下的所有项目（文件和目录）
            FTPFile[] items = listItems(sourceFtpClient, sourcePath);

            if (items == null || items.length == 0) {
                logger.info("任务 [{}] 源目录 {} 下没有项目", taskId, sourcePath);
                return;
            }

            // 过滤需要同步的项目
            List<FTPFile> itemsToSync = new ArrayList<>();
            for (FTPFile item : items) {
                if (".".equals(item.getName()) || "..".equals(item.getName())) {
                    continue;
                }

                // 过滤不需要同步的文件
                if (shouldIgnoreFile(item.getName())) {
                    continue;
                }

                String itemName = item.getName();
                String fullItemPath = sourcePath + "/" + itemName;

                // 检查项目是否已经稳定
                boolean isStable = false;
                if (item.isDirectory()) {
                    isStable = fileStateChecker.isDirectoryStable(sourceFtpClient, fullItemPath);
                } else {
                    isStable = fileStateChecker.isFileStable(sourceFtpClient, fullItemPath, item);
                }

                if (isStable) {
                    // 检查是否需要同步（新文件或已更改的文件）
                    if (shouldSyncItem(taskId, fullItemPath, item, detectModifiedFiles)) {
                        itemsToSync.add(item);
                    }
                }
            }

            // 执行同步
            if (!itemsToSync.isEmpty()) {
                if (ftpProperties.isEnableMultiThread()) {
                    syncItemsWithFtpMultiThread(taskId, sourceFtpClient, targetFtpClient, 
                        sourcePath, targetPath, itemsToSync, preserveTimestamps, largeFileThreshold);
                } else {
                    syncItemsWithFtpSingleThread(taskId, sourceFtpClient, targetFtpClient, 
                        sourcePath, targetPath, itemsToSync, preserveTimestamps, largeFileThreshold);
                }
            }
        } catch (IOException e) {
            logger.error("任务 [{}] 使用FTP处理目录时发生错误", taskId, e);
        } finally {
            // 关闭连接
            if (sourceFtpClient != null) {
                try {
                    sourceFtpClient.logout();
                    sourceFtpClient.disconnect();
                } catch (IOException e) {
                    logger.warn("任务 [{}] 关闭源FTP连接时发生错误", taskId, e);
                }
            }
            if (targetFtpClient != null) {
                try {
                    targetFtpClient.logout();
                    targetFtpClient.disconnect();
                } catch (IOException e) {
                    logger.warn("任务 [{}] 关闭目标FTP连接时发生错误", taskId, e);
                }
            }
        }
    }

    /**
     * 使用本地文件拷贝进行同步
     *
     * @param taskId 任务ID
     * @param sourcePath 源路径
     * @param localTargetPath 本地目标路径
     * @param detectModifiedFiles 是否检测已修改文件
     * @param preserveTimestamps 是否保持时间戳
     * @param largeFileThreshold 大文件阈值
     */
    private void checkAndSyncLocally(String taskId, String sourcePath, String localTargetPath, 
                                     boolean detectModifiedFiles, boolean preserveTimestamps, 
                                     long largeFileThreshold) {
        if (localTargetPath == null || localTargetPath.isEmpty()) {
            logger.warn("任务 [{}] 不使用FTP但未配置本地目标目录", taskId);
            return;
        }

        try {
            // 列出源目录下的所有项目（文件和目录）
            File sourceDir = new File(sourcePath);
            if (!sourceDir.exists() || !sourceDir.isDirectory()) {
                logger.warn("任务 [{}] 源目录 {} 不存在或不是目录", taskId, sourcePath);
                return;
            }

            File[] items = sourceDir.listFiles();

            if (items == null || items.length == 0) {
                logger.info("任务 [{}] 源目录 {} 下没有项目", taskId, sourcePath);
                return;
            }

            // 过滤需要同步的项目
            List<File> itemsToSync = new ArrayList<>();
            for (File item : items) {
                // 过滤不需要同步的文件
                if (shouldIgnoreFile(item.getName())) {
                    continue;
                }

                String itemName = item.getName();
                String fullItemPath = sourcePath + File.separator + itemName;

                // 检查项目是否已经稳定
                boolean isStable = false;
                if (item.isDirectory()) {
                    isStable = fileStateChecker.isLocalDirectoryStable(item);
                } else {
                    isStable = fileStateChecker.isLocalFileStable(item);
                }

                if (isStable) {
                    // 检查是否需要同步（新文件或已更改的文件）
                    if (shouldSyncItem(taskId, fullItemPath, item, detectModifiedFiles)) {
                        itemsToSync.add(item);
                    }
                }
            }

            // 执行同步
            if (!itemsToSync.isEmpty()) {
                if (ftpProperties.isEnableMultiThread()) {
                    syncItemsLocallyMultiThread(taskId, sourcePath, localTargetPath, itemsToSync, 
                        preserveTimestamps, largeFileThreshold);
                } else {
                    syncItemsLocallySingleThread(taskId, sourcePath, localTargetPath, itemsToSync, 
                        preserveTimestamps, largeFileThreshold);
                }
            }
        } catch (Exception e) {
            logger.error("任务 [{}] 本地处理目录时发生错误", taskId, e);
        }
    }

    /**
     * 创建FTP客户端连接
     *
     * @param ftpConfig FTP配置
     * @return FTPClient实例
     * @throws IOException IO异常
     */
    private FTPClient createFTPClient(FtpProperties.Ftp ftpConfig) throws IOException {
        FTPClient ftpClient = new FTPClient();
        ftpClient.connect(ftpConfig.getHost(), ftpConfig.getPort());
        ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
        ftpClient.enterLocalPassiveMode();
        ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
        return ftpClient;
    }

    /**
     * 单线程FTP同步
     */
    private void syncItemsWithFtpSingleThread(String taskId, FTPClient sourceFtpClient, FTPClient targetFtpClient, 
                                              String sourcePath, String targetPath, List<FTPFile> itemsToSync,
                                              boolean preserveTimestamps, long largeFileThreshold) {
        // 分类文件：大文件和小文件
        List<FTPFile> largeFiles = new ArrayList<>();
        List<FTPFile> smallFiles = new ArrayList<>();
        List<FTPFile> directories = new ArrayList<>();
        
        for (FTPFile item : itemsToSync) {
            if (item.isDirectory()) {
                directories.add(item);
            } else if (item.getSize() >= largeFileThreshold) {
                largeFiles.add(item);
            } else {
                smallFiles.add(item);
            }
        }
        
        // 处理大文件 - 逐个处理
        for (FTPFile largeFile : largeFiles) {
            try {
                String itemName = largeFile.getName();
                String fullItemPath = sourcePath + "/" + itemName;
                
                logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行文件推送
                String targetItemPath = targetPath + "/" + itemName;
                ftpService.copyFile(sourceFtpClient, fullItemPath, targetFtpClient, targetItemPath, largeFile);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            } catch (Exception e) {
                logger.error("任务 [{}] FTP同步大文件时发生错误", taskId, e);
            }
        }
        
        // 处理小文件 - 批量处理
        try {
            for (FTPFile smallFile : smallFiles) {
                String itemName = smallFile.getName();
                String fullItemPath = sourcePath + "/" + itemName;
                
                logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行文件推送
                String targetItemPath = targetPath + "/" + itemName;
                ftpService.copyFile(sourceFtpClient, fullItemPath, targetFtpClient, targetItemPath, smallFile);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            }
        } catch (Exception e) {
            logger.error("任务 [{}] FTP同步小文件时发生错误", taskId, e);
        }
        
        // 处理目录 - 逐个处理
        for (FTPFile directory : directories) {
            try {
                String itemName = directory.getName();
                String fullItemPath = sourcePath + "/" + itemName;
                
                logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行目录推送
                String targetItemPath = targetPath + "/" + itemName;
                ftpService.copyDirectory(sourceFtpClient, fullItemPath, targetFtpClient, targetItemPath);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            } catch (Exception e) {
                logger.error("任务 [{}] FTP同步目录时发生错误", taskId, e);
            }
        }
    }

    /**
     * 多线程FTP同步 - 根据文件大小分类处理
     */
    private void syncItemsWithFtpMultiThread(String taskId, FTPClient sourceFtpClient, FTPClient targetFtpClient, 
                                             String sourcePath, String targetPath, List<FTPFile> itemsToSync,
                                             boolean preserveTimestamps, long largeFileThreshold) {
        // 分类文件：大文件和小文件
        List<FTPFile> largeFiles = new ArrayList<>();
        List<FTPFile> smallFiles = new ArrayList<>();
        List<FTPFile> directories = new ArrayList<>();
        
        for (FTPFile item : itemsToSync) {
            if (item.isDirectory()) {
                directories.add(item);
            } else if (item.getSize() >= largeFileThreshold) {
                largeFiles.add(item);
            } else {
                smallFiles.add(item);
            }
        }
        
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        
        // 处理大文件 - 每个大文件单独线程处理
        for (FTPFile largeFile : largeFiles) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为每个大文件创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            String itemName = largeFile.getName();
                            String fullItemPath = sourcePath + "/" + itemName;
                            
                            logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行文件推送
                            String targetItemPath = targetPath + "/" + itemName;
                            ftpService.copyFile(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath, largeFile);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭大文件源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭大文件目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步大文件时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为每个大文件创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            String itemName = largeFile.getName();
                            String fullItemPath = sourcePath + "/" + itemName;
                            
                            logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行文件推送
                            String targetItemPath = targetPath + "/" + itemName;
                            ftpService.copyFile(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath, largeFile);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭大文件源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭大文件目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步大文件时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 处理小文件 - 批量处理
        if (!smallFiles.isEmpty()) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为小文件批次创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            for (FTPFile smallFile : smallFiles) {
                                String itemName = smallFile.getName();
                                String fullItemPath = sourcePath + "/" + itemName;
                                
                                logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                                System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                                // 执行文件推送
                                String targetItemPath = targetPath + "/" + itemName;
                                ftpService.copyFile(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath, smallFile);

                                // 记录同步时间
                                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                                fileStateChecker.clearDirectoryRecord(fullItemPath);
                            }
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭小文件源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭小文件目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步小文件时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为小文件批次创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            for (FTPFile smallFile : smallFiles) {
                                String itemName = smallFile.getName();
                                String fullItemPath = sourcePath + "/" + itemName;
                                
                                logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                                System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                                // 执行文件推送
                                String targetItemPath = targetPath + "/" + itemName;
                                ftpService.copyFile(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath, smallFile);

                                // 记录同步时间
                                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                                fileStateChecker.clearDirectoryRecord(fullItemPath);
                            }
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭小文件源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭小文件目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步小文件时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 处理目录 - 每个目录单独线程处理
        for (FTPFile directory : directories) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为每个目录创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            String itemName = directory.getName();
                            String fullItemPath = sourcePath + "/" + itemName;
                            
                            logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行目录推送
                            String targetItemPath = targetPath + "/" + itemName;
                            ftpService.copyDirectory(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭目录源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭目录目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步目录时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 为每个目录创建独立的FTP连接
                        FtpProperties.Ftp ftpConfig = getFtpConfigForTask(taskId);
                        FTPClient threadSourceClient = createFTPClient(ftpConfig);
                        FTPClient threadTargetClient = createFTPClient(ftpConfig);
                        
                        try {
                            String itemName = directory.getName();
                            String fullItemPath = sourcePath + "/" + itemName;
                            
                            logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行目录推送
                            String targetItemPath = targetPath + "/" + itemName;
                            ftpService.copyDirectory(threadSourceClient, fullItemPath, threadTargetClient, targetItemPath);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        } finally {
                            // 关闭线程专用的FTP连接
                            try {
                                threadSourceClient.logout();
                                threadSourceClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭目录源FTP连接时发生错误", taskId, e);
                            }
                            
                            try {
                                threadTargetClient.logout();
                                threadTargetClient.disconnect();
                            } catch (IOException e) {
                                logger.warn("任务 [{}] 关闭目录目标FTP连接时发生错误", taskId, e);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程FTP同步目录时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    }

    /**
     * 单线程本地同步
     */
    private void syncItemsLocallySingleThread(String taskId, String sourcePath, String localTargetPath, List<File> itemsToSync,
                                              boolean preserveTimestamps, long largeFileThreshold) {
        // 分类文件：大文件和小文件
        List<File> largeFiles = new ArrayList<>();
        List<File> smallFiles = new ArrayList<>();
        List<File> directories = new ArrayList<>();
        
        for (File item : itemsToSync) {
            if (item.isDirectory()) {
                directories.add(item);
            } else if (item.length() >= largeFileThreshold) {
                largeFiles.add(item);
            } else {
                smallFiles.add(item);
            }
        }
        
        // 处理大文件 - 逐个处理
        for (File largeFile : largeFiles) {
            try {
                String itemName = largeFile.getName();
                String fullItemPath = sourcePath + File.separator + itemName;
                
                logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行文件拷贝
                String targetItemPath = localTargetPath + File.separator + itemName;
                localFileService.copyFile(fullItemPath, targetItemPath);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            } catch (Exception e) {
                logger.error("任务 [{}] 本地同步大文件时发生错误", taskId, e);
            }
        }
        
        // 处理小文件 - 批量处理
        try {
            for (File smallFile : smallFiles) {
                String itemName = smallFile.getName();
                String fullItemPath = sourcePath + File.separator + itemName;
                
                logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行文件拷贝
                String targetItemPath = localTargetPath + File.separator + itemName;
                localFileService.copyFile(fullItemPath, targetItemPath);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            }
        } catch (Exception e) {
            logger.error("任务 [{}] 本地同步小文件时发生错误", taskId, e);
        }
        
        // 处理目录 - 逐个处理
        for (File directory : directories) {
            try {
                String itemName = directory.getName();
                String fullItemPath = sourcePath + File.separator + itemName;
                
                logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                // 执行目录拷贝
                String targetItemPath = localTargetPath + File.separator + itemName;
                localFileService.copyDirectory(fullItemPath, targetItemPath);

                // 记录同步时间
                syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                fileStateChecker.clearDirectoryRecord(fullItemPath);
            } catch (Exception e) {
                logger.error("任务 [{}] 本地同步目录时发生错误", taskId, e);
            }
        }
    }

    /**
     * 多线程本地同步 - 根据文件大小分类处理
     */
    private void syncItemsLocallyMultiThread(String taskId, String sourcePath, String localTargetPath, List<File> itemsToSync,
                                             boolean preserveTimestamps, long largeFileThreshold) {
        // 分类文件：大文件和小文件
        List<File> largeFiles = new ArrayList<>();
        List<File> smallFiles = new ArrayList<>();
        List<File> directories = new ArrayList<>();
        
        for (File item : itemsToSync) {
            if (item.isDirectory()) {
                directories.add(item);
            } else if (item.length() >= largeFileThreshold) {
                largeFiles.add(item);
            } else {
                smallFiles.add(item);
            }
        }
        
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        
        // 处理大文件 - 每个大文件单独线程处理
        for (File largeFile : largeFiles) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        String itemName = largeFile.getName();
                        String fullItemPath = sourcePath + File.separator + itemName;
                        
                        logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                        System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                        // 执行文件拷贝
                        String targetItemPath = localTargetPath + File.separator + itemName;
                        localFileService.copyFile(fullItemPath, targetItemPath);

                        // 记录同步时间
                        syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                        fileStateChecker.clearDirectoryRecord(fullItemPath);
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步大文件时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        String itemName = largeFile.getName();
                        String fullItemPath = sourcePath + File.separator + itemName;
                        
                        logger.info("任务 [{}] 大文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                        System.out.println("任务 [" + taskId + "] 大文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                        // 执行文件拷贝
                        String targetItemPath = localTargetPath + File.separator + itemName;
                        localFileService.copyFile(fullItemPath, targetItemPath);

                        // 记录同步时间
                        syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                        fileStateChecker.clearDirectoryRecord(fullItemPath);
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步大文件时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 处理小文件 - 批量处理
        if (!smallFiles.isEmpty()) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        for (File smallFile : smallFiles) {
                            String itemName = smallFile.getName();
                            String fullItemPath = sourcePath + File.separator + itemName;
                            
                            logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行文件拷贝
                            String targetItemPath = localTargetPath + File.separator + itemName;
                            localFileService.copyFile(fullItemPath, targetItemPath);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步小文件时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        for (File smallFile : smallFiles) {
                            String itemName = smallFile.getName();
                            String fullItemPath = sourcePath + File.separator + itemName;
                            
                            logger.info("任务 [{}] 小文件 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                            System.out.println("任务 [" + taskId + "] 小文件 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                            // 执行文件拷贝
                            String targetItemPath = localTargetPath + File.separator + itemName;
                            localFileService.copyFile(fullItemPath, targetItemPath);

                            // 记录同步时间
                            syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                            fileStateChecker.clearDirectoryRecord(fullItemPath);
                        }
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步小文件时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 处理目录 - 每个目录单独线程处理
        for (File directory : directories) {
            if (executorService != null) {
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        String itemName = directory.getName();
                        String fullItemPath = sourcePath + File.separator + itemName;
                        
                        logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                        System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                        // 执行目录拷贝
                        String targetItemPath = localTargetPath + File.separator + itemName;
                        localFileService.copyDirectory(fullItemPath, targetItemPath);

                        // 记录同步时间
                        syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                        fileStateChecker.clearDirectoryRecord(fullItemPath);
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步目录时发生错误", taskId, e);
                    }
                }, executorService);
                futures.add(future);
            } else {
                // 如果线程池未初始化，使用默认的common pool
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        String itemName = directory.getName();
                        String fullItemPath = sourcePath + File.separator + itemName;
                        
                        logger.info("任务 [{}] 目录 {} 已经更新完成 (线程: {})", taskId, fullItemPath, Thread.currentThread().getName());
                        System.out.println("任务 [" + taskId + "] 目录 " + fullItemPath + " 已经更新完成 (线程: " + Thread.currentThread().getName() + ")");

                        // 执行目录拷贝
                        String targetItemPath = localTargetPath + File.separator + itemName;
                        localFileService.copyDirectory(fullItemPath, targetItemPath);

                        // 记录同步时间
                        syncedItems.put(taskId + ":" + fullItemPath, System.currentTimeMillis());
                        fileStateChecker.clearDirectoryRecord(fullItemPath);
                    } catch (Exception e) {
                        logger.error("任务 [{}] 多线程本地同步目录时发生错误", taskId, e);
                    }
                });
                futures.add(future);
            }
        }
        
        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    }

    /**
     * 获取任务的FTP配置
     */
    private FtpProperties.Ftp getFtpConfigForTask(String taskId) {
        // 从taskId中提取任务索引
        String[] parts = taskId.split("-");
        if (parts.length >= 3) {
            try {
                int taskIndex = Integer.parseInt(parts[1]);
                if (taskIndex < ftpProperties.getSyncTasks().size()) {
                    FtpProperties.SyncTask task = ftpProperties.getSyncTasks().get(taskIndex);
                    if (task.getFtp() != null) {
                        return task.getFtp();
                    }
                }
            } catch (NumberFormatException e) {
                // 忽略解析错误
            }
        }
        // 返回全局FTP配置
        return ftpProperties.getFtp();
    }

    /**
     * 判断是否应该同步指定的项目
     *
     * @param taskId 任务ID
     * @param itemPath 项目路径
     * @param item 项目对象（FTPFile或File）
     * @param detectModifiedFiles 是否检测已修改文件
     * @return true表示应该同步，false表示不需要同步
     */
    private boolean shouldSyncItem(String taskId, String itemPath, Object item, boolean detectModifiedFiles) {
        String key = taskId + ":" + itemPath;
        Long lastSyncTime = syncedItems.get(key);
        
        // 如果从未同步过，则需要同步
        if (lastSyncTime == null) {
            return true;
        }
        
        // 如果不检测已同步文件的修改，则跳过已同步的文件
        if (!detectModifiedFiles) {
            logger.debug("任务 [{}] 检测已同步文件修改功能已关闭，跳过已同步项目 {}", taskId, itemPath);
            return false;
        }
        
        // 如果是目录，检查目录的最后修改时间
        if (item instanceof FTPFile && ((FTPFile) item).isDirectory()) {
            FTPFile ftpFile = (FTPFile) item;
            long currentItemModifiedTime = ftpFile.getTimestamp() != null ? ftpFile.getTimestamp().getTimeInMillis() : 0;
            boolean shouldSync = currentItemModifiedTime > lastSyncTime;
            if (!shouldSync) {
                logger.debug("任务 [{}] 目录 {} 已同步且未更改，跳过同步", taskId, itemPath);
            }
            return shouldSync;
        }
        
        if (item instanceof File && ((File) item).isDirectory()) {
            File file = (File) item;
            long currentItemModifiedTime = file.lastModified();
            boolean shouldSync = currentItemModifiedTime > lastSyncTime;
            if (!shouldSync) {
                logger.debug("任务 [{}] 目录 {} 已同步且未更改，跳过同步", taskId, itemPath);
            }
            return shouldSync;
        }
        
        // 检查文件是否在上次同步后有修改
        long currentItemModifiedTime = 0;
        if (item instanceof FTPFile) {
            FTPFile ftpFile = (FTPFile) item;
            currentItemModifiedTime = ftpFile.getTimestamp() != null ? ftpFile.getTimestamp().getTimeInMillis() : 0;
        } else if (item instanceof File) {
            File file = (File) item;
            currentItemModifiedTime = file.lastModified();
        }
        
        // 如果文件在上次同步后有修改，则需要重新同步
        boolean shouldSync = currentItemModifiedTime > lastSyncTime;
        if (!shouldSync) {
            logger.debug("任务 [{}] 项目 {} 已同步且未更改，跳过同步", taskId, itemPath);
        }
        return shouldSync;
    }

    /**
     * 判断是否应该忽略指定的文件
     *
     * @param fileName 文件名
     * @return true表示应该忽略，false表示不需要忽略
     */
    private boolean shouldIgnoreFile(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return true;
        }

        // 检查是否以点开头（隐藏文件）
        if (fileName.startsWith(".")) {
            // 特殊处理.swp文件
            if (fileName.endsWith(".swp")) {
                return true;
            }
        }

        // 检查文件扩展名
        for (String extension : IGNORED_EXTENSIONS) {
            if (fileName.endsWith(extension)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 列出指定FTP目录下的所有项目
     *
     * @param ftpClient FTP客户端
     * @param directory 目录路径
     * @return 项目列表
     * @throws IOException IO异常
     */
    private FTPFile[] listItems(FTPClient ftpClient, String directory) throws IOException {
        ftpClient.changeWorkingDirectory(directory);
        return ftpClient.listFiles();
    }
    
    @Override
    protected void finalize() throws Throwable {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
        }
        super.finalize();
    }
}